package com.tanhua.dubbo.server.service;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
import com.tanhua.dubbo.server.exception.UnauthorizedException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

/**
 * 这个类用来处理环信的请求服务
 */
@Service
@Slf4j
public class RequestService {
    @Autowired
    private TokenService tokenService;

    /**
     * 向环信发送请求
     *
     * @param url 地址
     * @param body 参数
     * @param method 请求方法
     * @return 响应对象
     */
    @Retryable(value = UnauthorizedException.class, maxAttempts = 5, backoff = @Backoff(delay = 2000L, multiplier = 2))
    public HttpResponse execute(String url, String body, Method method) {
        //调用TokenService的方法，获得token
        String token = tokenService.getToken();

        HttpRequest httpRequest;

        //判断请求方法是什么类型的
        switch (method) {
            case POST: {
                httpRequest = HttpRequest.post(url);
                break;
            }
            case DELETE: {
                httpRequest = HttpRequest.delete(url);
                break;
            }
            case PUT: {
                httpRequest = HttpRequest.put(url);
                break;
            }
            case GET: {
                httpRequest = HttpRequest.get(url);
                break;
            }
            default: {
                return null;
            }
        }

        //通用请求：固定的两个请求头，token和body取决于传参
        HttpResponse httpResponse = httpRequest.header("Content-Type", "application/json")
                .header("Authorization", "Bearer " + token)
                .body(body)
                .timeout(20000)
                .execute();

        //判断响应的状态是不是401,401表示token过期，就执行重试
        if (httpResponse.getStatus() == 401){
            //刷新token：1.重新请求环信获得token 2.将token缓存到redis中
            tokenService.refreshToken();

            //抛出异常，执行重试
            throw new UnauthorizedException(url,body,method);
        }

        //将响应对象返回
        return httpResponse;

    }

    /**
     * 全部重试失败后执行
     * @param e
     * @return
     */
    @Recover
    public HttpResponse recover(UnauthorizedException e) {
        log.error("获取token失败！url = " + e.getUrl() + ", body = " + e.getBody() + ", method = " + e.getMethod().toString());
        //如果重试5次后，依然不能获取到token，说明网络或账号出现了问题，只能返回null了，后续的请求将无法再执行
        return null;
    }
}
